home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC-SIG: World of Games
/
PC-SIG World of Games (CDRM1080710) (1993).iso
/
ENT
/
DISK2468.ZIP
/
MM
/
POPUP.C
< prev
next >
Wrap
Text File
|
1990-05-04
|
13KB
|
400 lines
/********************************************************************
* Popup window toolkit for Turbo C (popup.c) *
********************************************************************/
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
#include <conio.h>
#include <string.h>
#include <process.h>
#include "\tc\myincs\popup.h"
#include "\tc\myincs\mouse.h"
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
/*
* Global data definitions
*/
windesc *base_win = NULL; /* The "Base Window" pointer */
windesc *curr_win = NULL; /* The current window pointer */
/* Color sets for color monitors */
/* {border_type, border_color, text_color, title_color, hilite_color} */
wincolors defcolors = {1, 23, 30, 27, 94 };
wincolors invcolors = {1, 112, 112, 112, 15 };
wincolors monocolors = {1, 7, 15, 15, 12 };
wincolors errcolors = {1, 79, 79, 79, 4 };
wincolors msgcolors = {1, 47, 47, 46, 112 };
wincolors graycolors = {1, 116, 127, 127, 127 };
/* variables internal to popup.c */
static windesc *top_win; /* window stack pointer */
static void chg_win(windesc *this);
static windesc *make_window_node(void);
static windesc *push_window_node(void);
static void dispose_window_node(windesc *w);
void init_win(void)
/* init_win initializes the internal variables for the popup windows
package. This function creates a base window "base_win" which
represents the entire screen.
This function MUST be called before any popup routines are used. */
{
struct text_info ti; /* Turbo C predefined structure */
base_win = make_window_node(); /* allocate a window node */
gettextinfo(&ti); /* get base window coords */
base_win->xul = ti.winleft - 1; /* but our coords include border ! */
base_win->xlr = ti.winright + 1;
base_win->yul = ti.wintop - 1;
base_win->ylr = ti.winbottom + 1;
base_win->wd = ti.screenwidth + 2;
base_win->ht = ti.screenheight + 2;
base_win->xsave = ti.curx;
base_win->ysave = ti.cury;
base_win->wc = monocolors; /* default to monochrome colors */
base_win->wc.text_color = ti.attribute;/* but use current window color */
base_win->name = "base"; /* window has no title */
base_win->wtype = tile; /* no saved image underneath */
base_win->wc.border_type = 0; /* has no border either */
top_win = base_win; /* set up window stack */
curr_win = base_win;
}
windesc *draw_win(int x,int y,int wd, int ht, char *title,
enum windowtype wt, wincolors *wc)
/* draw_win creates a new window at a designated screen location.
All window coordinates include the border! Note that the
turbo-C window funciton does not know about the border, and that
its coordinates are actually "inside" the border.
Besides the usual coordinates for (x,y), you can use the following
codes:
x = CTRWIN (Center window in x direction)
y = CTRWIN (Center window in y direction)
*/
{
windesc *w;
int xsave, ysave;
mouse_off(1); /* hide mouse cursor during screen updates */
w = push_window_node(); /* create and link up a window node */
/* check for valid window size */
wd = MAX(wd,3);
wd = MIN(wd,80);
ht = MAX(ht,3);
ht = MIN(ht,25);
/* check for centering coordinates and current coordinates.
Reminder: these are absolute coordinates ! */
if (x == CTRWIN) x = (80-wd) /2;
if (y == CTRWIN) y = (25-ht) /2;
/* Check for valid coordinates. Coordinates (0,0) are valid only for
borderless windows, (the actual window will start at (1,1)). */
if (wc->border_type) {
x = MAX(x,1);
y = MAX(y,1);
}
else {
x = MAX(x,0);
y = MAX(y,0);
}
if ((x+wd) > 80) x = 80-wd+1;
if ((y+ht) > 25) y = 25-ht+1;
/* store the window parameters */
w->wd = wd; w->ht = ht; w->xul = x; w->yul = y;
w->xlr = x + w->wd-1; w->ylr = w->yul + w->ht -1;
w->wc = *wc; /* set up our set of colors */
w->xsave = 1; w->ysave = 1;
w->wtype = wt; w->name = strdup(title);
/* allocate and save image underneath if a popup window */
if (wt == popup) {
w->image = calloc(wd*ht,2);
swap_image(w);
}
/* Ready to draw box and title. To do this we must be in base or
"absolute" coords. But we must be careful to save the base cursor
coords cause draw box and centerstr will change them on us. */
if (curr_win == base_win) {
xsave = wherex();
ysave = wherey();
}
else {
xsave = base_win->xsave;
ysave = base_win->ysave;
}
chg_win(base_win);
draw_box(w->xul,w->yul,w->xlr,w->ylr,w->wc.border_type,w->wc.border_color);
centerstr(w->xul,w->yul,w->xlr,w->yul,w->name,w->wc.title_color);
gotoxy(xsave,ysave); /* restore base window cursor coords */
chg_win(w); /* Now select new window */
clr_win(); /* and clear it */
mouse_on(1); /* restore mouse state */
return w; /* return new window pointer */
}
void view_win(windesc *this, int select)
/* If select = 1, then view_win moves "this" window to the
top of the stack and makes it the active window.
If select = 0, then the window is removed from the stack and erased.
Node that no moves take place if already at the top.
If this is merely a tiled window, then it is just selected. */
{
windesc *p;
if (select && this == top_win) return;
mouse_off(1); /* make sure mouse is hidden */
/* if this is a popup window, move its image to the top */
if (this->wtype == popup) {
p = top_win;
while (p != this) { /* hide all window above */
swap_image(p);
p = p->under;
}
swap_image(this); /* and then this window */
p = this; /* then put rest of windows back */
while(p != top_win) {
p = p->over;
swap_image(p);
}
}
/* link up window underneath this one, with the window above it */
if (this == top_win) { /* if this == top_win here, then it is also */
this->under->over = NULL; /* true that we're removing it for good */
top_win = this->under;
}
else {
this->under->over = this->over;
this->over->under = this->under;
}
if (select) {
top_win->over = this; /* move window to the top */
this->under = top_win;
top_win = this;
swap_image(this); /* put back it's image. Does nothing if tiled */
chg_win(this); /* change window */
}
else {
chg_win(top_win); /* might as well select top window */
dispose_window_node(this); /* but do before free old window */
}
mouse_on(1); /* restore mouse state */
}
static void chg_win(windesc *this)
/* internal routine to select a window */
{
curr_win->xsave = wherex();
curr_win->ysave = wherey();
window(this->xul+1, this->yul+1, this->xlr-1, this->ylr-1);
textattr(this->wc.text_color); /* restore window color and cursor */
gotoxy(this->xsave, this->ysave);
curr_win = this; /* selected window is active */
}
void swap_image(windesc *w)
/* This routine swaps the image buffer of a window with what is on the
screen. If the window is not a popup window, then nothing happens. */
{
int xstart, ystart, xfin, yfin;
char *temp_image;
unsigned int nbytes;
if (w->wtype == popup) {
xstart = w->xul; ystart = w->yul;
xfin = w->xlr; yfin = w->ylr;
if (!w->wc.border_type) { /* don't swap border area if no border */
xstart++; ystart++;
xfin--; yfin--;
}
nbytes = (xfin-xstart+1)*(yfin-ystart+1)*2;
mouse_off(1); /* hide cursor during screen update */
temp_image = malloc(nbytes);
gettext(xstart, ystart, xfin, yfin, temp_image);
puttext(xstart, ystart, xfin, yfin, (void *)w->image);
memcpy(w->image, temp_image, nbytes);
free(temp_image);
mouse_on(1); /* restore mouse cursor */
}
}
void clr_win(void)
/* High level clear window. Supports the mouse cursor, and uses
the text_color of the current window when clearing it. */
{
mouse_off(1);
textattr(curr_win->wc.text_color);
clrscr();
mouse_on(1);
}
void mprintf(char *fmt,...)
/* mprintf is a high level printf-like funciton that calls printf (so it
knows about the current window), but also takes care of them mouse.
NOTE: the formatting must not exceed 255 characters ! */
{
va_list arg_ptr;
char t[255];
va_start(arg_ptr,wd);
vsprintf(t,fmt,arg_ptr); /* internal format function */
mouse_off(1); /* hide mouse cursor during screen update */
cprintf("%s", t); /* print the string with scrolling supported */
mouse_on(1); /* restore mouse cursor */
va_end(arg_ptr);
}
void prtfstr(int x, int y, char *fmt, unsigned char attr, int wd,...)
/* prtfstr prints a formatted string in the current window. prfstr is
similar to cprintf except that it doesn't support wrap-around, in fact,
it goes to great lengths to get around it. If the string is too long
to fit in the window, it will be truncated.
If attr != 0, the string will be printed with that color, otherwise
the color will be left alone.
If wd < 0 and the length of the formatted string = 1, then prtfstr
will print the one-character string abs(wd) times. This is useful
for filling a line with a character.
NOTE: The formatting must not exceed 255 characters ! */
{
va_list arg_ptr;
char t[255];
int len, i, n, xa, ya, fillflag;
static texel line[80]; /* text image buffer */
va_start(arg_ptr,wd);
vsprintf(t, fmt, arg_ptr); /* internal format function */
va_end(arg_ptr);
n = abs(wd); /* compute and bounds check desired width */
n = MIN(n, curr_win->wd-x-1);
xa = curr_win->xul + x;
ya = curr_win->yul + y;
len = MIN(strlen(t), n); /* keep string inside the window */
t[len] = 0; /* by truncating if necessary */
if (len) { /* only do non-null strings */
if (wd < 0 && (strlen(t) == 1)) {
fillflag = 1;
len = n;
}
else {
fillflag = 0;
}
mouse_off(1); /* remember to hide mouse */
gettext(xa, ya, xa+len-1, ya, line); /* extract text image */
for (i=0; i<len; i++) {
if (fillflag) line[i].ch = *t;
else line[i].ch = t[i];
if (attr) line[i].attr = attr;
}
puttext(xa, ya, xa+len-1, ya, line); /* put it back */
mouse_on(1); /* restore mouse */
if (x+len == curr_win->wd-1)
x--; /* Keep cursor in window */
gotoxy(x+len, y); /* then move it to end of string */
}
else { /* for null strings, just move cursor */
gotoxy(x,y);
}
}
void centerstr(int xul, int yul, int xlr, int ylr, char *s, unsigned char a)
/* centerstr prints a string centered between the relative coord's
(xul,yul) and (xlr,ylr), with attribute a. */
{
int xs, ys, wd;
if (*s != 0) {
mouse_off(1);
wd = xlr-xul+1;
if ((xs = (wd-strlen(s)) / 2 + xul) < xul) xs = xul;
if ((ys = (ylr-yul+1) / 2 + yul) < yul) ys = yul;
prtfstr(xs, ys, s, a, wd);
mouse_on(1);
}
}
void draw_box(int xul, int yul, int xlr, int ylr, int btype, int attr)
/* Draws a box at the upper left (xul,yul) and lower right
(xlr,ylr) coords with given attribute. If btype = 0, no box is drawn,
if btype = 1, a single line box is drawn, if btype = 2, a doulble line
box is drawn.
*/
{
static int boxcar[2][6] = /* graphics characters for a box */
{
{218,196,191,179,192,217}, /* single line box */
{201,205,187,186,200,188} /* double line box */
};
int i, hzchar, vtchar, oldattr;
texel t;
struct text_info ti;
if (btype)
{
mouse_off(1);
gettextinfo(&ti); /* save old text attribute */
oldattr = ti.attribute;
textattr(attr);
hzchar = boxcar[btype-1][1];
vtchar = boxcar[btype-1][3];
/* draw top and bottom sides */
gotoxy(xul+1,yul);
for (i = xul+1; i < xlr; i++) putch(hzchar);
gotoxy(xul+1,ylr);
for (i = xul+1; i < xlr; i++) putch(hzchar);
/* draw vertical sides */
for (i = yul+1; i < ylr; i++)
{
gotoxy(xul,i);
putch(vtchar);
gotoxy(xlr,i);
putch(vtchar);
}
/* draw corners */
gotoxy(xul,yul); putch(boxcar[btype-1][0]); /* upper left */
gotoxy(xlr,yul); putch(boxcar[btype-1][2]); /* upper right */
gotoxy(xul,ylr); putch(boxcar[btype-1][4]); /* lower left */
/* can't write lower right corner via putch, due to possible
scroll problems, so must do it a roundabout way */
gettext(xlr,ylr,xlr,ylr,&t);
t.ch = boxcar[btype-1][5];
t.attr = attr;
puttext(xlr,ylr,xlr,ylr,&t);
textattr(oldattr); /* restore old attribute */
mouse_on(1);
}
}
static windesc *make_window_node(void)
/* make_window_node allocates room for a new window structure,
and initializes it's links to NULL. */
{
windesc *q;
q = (windesc *)malloc(sizeof(windesc));
q->image = NULL;
q->under = NULL;
q->over = NULL;
return q;
}
static windesc *push_window_node(void)
/* push_window_node "pushes" the window w onto the window stack. */
{
windesc *q;
q = make_window_node(); /* allocate a window node */
top_win->over = q; /* link top of stack to new node */
q->under = top_win; /* link lew node to top of stack */
top_win = q; /* set top of stack to new node */
return q;
}
static void dispose_window_node(windesc *w)
/* Dispose_window_node frees up the image save area of the window,
and the window structure itself. */
{
if (w != NULL) { /* savety test for base window */
if (w->wtype == popup) free(w->image);
free(w->name); /* free up window title */
free(w); /* and then the structure itself */
}
}